package com.yunhe.option.service.base.impl;

import com.yunhe.common.constant.CacheConsts;
import com.yunhe.option.domain.base.Area;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.exception.UniqueConstraintsException;
import com.yunhe.common.model.PageParam;
import com.yunhe.option.repository.base.AreaRepository;
import com.yunhe.option.service.base.AreaService;
import com.yunhe.common.util.RedisClient;
import com.yunhe.common.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * 地区Service
 *
 * @author liuronglei
 * @desc 地区服务类实现
 */
@Service
public class AreaServiceImpl implements AreaService {
    @Autowired
    AreaRepository areaRepository;
    @Autowired
    private RedisClient redisClient;


    /**
     * 地区处理和判断
     *
     * @param area 地区对象
     */
    private void processBeforeSave(Area area)
            throws ArgumentErrorException, UniqueConstraintsException {
        //判断地区编号是否为空
        if (StringUtil.isEmpty(area.getName())
                || StringUtil.isEmpty(area.getTitle())) {
            throw new ArgumentErrorException("地区代码、地区编号、地区标题不能为空");
        }
        //判断地区编号是否已存在
        Area areaByName = this.findByName(area.getName());
        if (areaByName != null) {
            if (area.getId() == null || areaByName.getId().longValue() != area.getId().longValue()) {
                throw new UniqueConstraintsException("该地区编号已存在");
            }
        }
    }

//    /**
//     * 移除重复的孩子地区
//     * @param list 地区列表
//     */
//    private void removeRepeatChild(List<Area> list) {
//        if (list != null && list.size() > 0) {
//            //保存重复的ID
//            Map<Long, Object> repeatIdMap = new HashMap<>();
//            //第一次循环，获得所有孩子节点ID
//            for (Area area : list) {
//                List<Area> children =  area.getChildren();
//                if (children != null && children.size() > 0) {
//                    for (Area child: children) {
//                        repeatIdMap.put(child.getId(), null);
//                    }
//                }
//            }
//            //根据是否是孩子节点移除元素
//            for (int i = list.size() - 1; i >= 0; i--) {
//                Area area = list.get(i);
//                if (repeatIdMap.containsKey(area.getId())) {
//                    list.remove(i);
//                }
//            }
//        }
//    }

    /**
     * 更新父地区关系（添加到父地区）
     *
     * @param area     子地区对象
     * @param parentId 父地区ID
     */
    private void updateParent(Area area, Long parentId) throws ObjectNotFoundException {
        if (area != null) {
            areaRepository.unbindParentAreaById(area.getId());
        }
        if (parentId != null && parentId != -1) {
            Area parentArea = findById(parentId);
            if (parentArea == null) {
                throw new ObjectNotFoundException("找不到ID为" + parentId + "的父地区");
            }
            areaRepository.bindChildAreaById(parentId, area.getId());
        }
    }

    /**
     * 新增地区
     *
     * @param area 新增对象
     */
    @Override
    @Transactional
    public Area create(Area area, Long parentId)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        area.setId(null);
        processBeforeSave(area);
        Area newArea = areaRepository.save(area);
        //绑定父地区关系
        if (parentId != null) {
            updateParent(newArea, parentId);
        }
        return newArea;
    }

    /**
     * 批量新增地区
     *
     * @param list 地区列表
     */
    @Override
    @Transactional
    public Iterable<Area> create(List<Area> list)
            throws ArgumentErrorException, UniqueConstraintsException {
        for (Area area : list) {
            area.setId(null);
            processBeforeSave(area);
        }
        return areaRepository.saveAll(list);
    }

    /**
     * 根据id删除地区
     *
     * @param areaId id
     */
    @Override
    @Transactional
    public void deleteById(Long areaId) {
        areaRepository.deleteById(areaId);
    }

    /**
     * 根据地区代码删除地区
     *
     * @param code 地区代码
     */
    @Override
    @Transactional
    public Long deleteByCode(Long code) {
        return areaRepository.deleteByCode(code);
    }

    /**
     * 根据地区编号删除地区
     *
     * @param name 地区编号
     */
    @Override
    @Transactional
    public Long deleteByName(String name) {
        return areaRepository.deleteByName(name);
    }

    /**
     * 更新地区（更新全部字段）
     *
     * @param area 要更新的地区对象
     */
    @Override
    @Transactional
    public Area update(Area area)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        boolean exists = area.getId() != null && areaRepository.existsById(area.getId());
        if (!exists) {
            throw new ObjectNotFoundException("找不到ID为" + area.getId() + "的地区");
        }
        processBeforeSave(area);
        return areaRepository.save(area);
    }

    /**
     * 更新地区（更新指定字段）
     *
     * @param areaId id
     * @param code   地区代码
     * @param name   地区编号
     * @param title  地区标题
     *               //     * @param adminArea 行政区
     */
    @Override
    public Area update(Long areaId,
                       String name,
                       String title,
                       String type,
                       Long parentId)
            throws ArgumentErrorException, ObjectNotFoundException, UniqueConstraintsException {
        Area area = this.findById(areaId);
        if (area == null) {
            throw new ObjectNotFoundException("找不到ID为" + area.getId() + "的地区");
        }
        Optional.ofNullable(name).ifPresent(area::setName);
        Optional.ofNullable(title).ifPresent(area::setTitle);
        Optional.ofNullable(type).ifPresent(area::setType);
        processBeforeSave(area);
        if (parentId != null) {
            updateParent(area, parentId);
        }
        return areaRepository.save(area);
    }

    /**
     * 根据ID获得地区对象
     *
     * @param id id
     */
    @Override
    public Area findById(Long id) {
//        return areaRepository.findById(id).get();
        return areaRepository.findById(id).orElse(null);
    }

    /**
     * 根据地区代码获得地区对象
     *
     * @param code 地区代码
     */
    @Override
    public Area findByCode(Long code) {
        return areaRepository.findByCode(code);
    }

    /**
     * 根据地区编号获得地区对象
     *
     * @param name 地区编号
     */
    @Override
    public Area findByName(String name) {
        return areaRepository.findByName(name);
    }

    /**
     * 根据地区标题获得地区对象
     *
     * @param title 地区标题
     */
    @Override
    public Area findByTitle(String title) {
        return areaRepository.findByTitle(title);
    }

    /**
     * 获得有单位关联的地区对象
     */
    @Override
    public Iterable<Area> findFirmAreas() {
        return areaRepository.findFirmAreas();
    }

    /**
     * 根据单位代码获得单位关联的地区对象
     *
     * @param firmCode 单位代码
     */
    @Override
    public Area findFirmArea(Long firmCode) {
        return areaRepository.findFirmArea(firmCode);
    }

    /**
     * 根据条件获得地区对象
     *
     * @param pageParam 分页对象
     */
    @Override
    public Iterable<Area> retrieve(String type,
                                   Long parentId,
                                   PageParam pageParam) {
        if (StringUtils.isNotEmpty(type)) {
            return areaRepository.findAreasByType(type);
        } else if (parentId != null) {
            return areaRepository.findChildrenArea(parentId);
        } else {
            List<Area> areas = redisClient.getAsList(CacheConsts.KEY.All_AREA.value(), Area.class);
            if (areas == null) {
                areas = (List<Area>)areaRepository.findAreas();
                redisClient.setObject(CacheConsts.KEY.All_AREA.value(), areas, CacheConsts.LIVE_TIME.DAY.value());
            }
            return areas;
        }
    }

    /**
     * 根据单位获取所属地区
     */
    @Override
    public Iterable<Area> findAreaByFirmId(Long firmId) {
        return areaRepository.findAreaByFirmId(firmId);
    }

    @Override
    public Iterable<Area> findChildren(Long areaId) {
        return areaRepository.findChildrenArea(areaId);
    }

    @Override
    public Area getAreaByStation(Long stationId) {
        return areaRepository.getAreaByStation(stationId);
    }

    @Override
    public Iterable<Area> findAreasWithStation() {
        return areaRepository.getAreaWithStation();
    }
}
